using System;
using System.Collections.Generic;
using System.Linq;
using Pay.Core;
using Pay.Data;
using Pay.DTO;
using Pay.IService;
using Pay.Service.Cache;
using Pay.TO;

namespace Pay.Service {
	public class RefundOrderService : ServiceBase, IRefundOrderService, IDisposable {
		private IUnitOfWork _iUnitOfWork;
		private IBillService _iBillService;

		public RefundOrderService(IUnitOfWork iUnitOfWork, IBillService iBillService)
			: base(iUnitOfWork) {
			_iUnitOfWork = iUnitOfWork;
			_iBillService = iBillService;
		}

		/// <summary>
		/// 查询
		/// </summary>
		/// <param name="refundQuery"></param>
		/// <returns></returns>
		public PagedResult<refund_order_dto> Get(RefundQuery refundQuery) {
			var filter = PredicateBuilder.True<RefundOrder>();
			if (!string.IsNullOrEmpty(refundQuery.order_no))
				filter = filter.And(c => c.Order.OrderNo == refundQuery.order_no
								   || c.OrderNo == refundQuery.order_no || c.PayInfo.PayNo == refundQuery.order_no);
			if (refundQuery.status != RefundStatus.None)
				filter = filter.And(c => c.Status == refundQuery.status);
			if (refundQuery.user_id > 0)
				filter = filter.And(c => c.Order.MerchantId == refundQuery.user_id);
			if (!string.IsNullOrEmpty(refundQuery.payment_type))
				filter = filter.And(c => c.PayInfo.PayCode == refundQuery.payment_type);
			if (refundQuery.start_time.HasValue && refundQuery.end_time.HasValue)
				filter = filter.And(c => c.ApplyTime >= refundQuery.start_time.Value.ToUnix() && c.ApplyTime <= refundQuery.end_time.Value.ToUnix());
			if (!string.IsNullOrEmpty(refundQuery.q))
				filter = filter.And(c => c.Order.Merchant.Mobile == refundQuery.q || c.Order.Merchant.Name.Contains(refundQuery.q)
				|| c.Order.Merchant.Mobile.Contains(refundQuery.q));
			return context.RefundOrders.FromCachePaged<RefundOrder, refund_order_dto>(refundQuery.page, refundQuery.size, filter, orderBy => orderBy.OrderByDescending(c => c.ApplyTime), "RefundOrder");
		}

		/// <summary>
		/// 查询退款订单
		/// </summary>
		/// <param name="refund_id"></param>
		/// <returns></returns>
		public refund_order_dto Get(long refund_id) {
			return context.RefundOrders.Where(c => c.Id == refund_id).FromCacheFirstOrDefault<RefundOrder, refund_order_dto>("RefundOrder");
		}

		/// <summary>
		/// 查询退款退货订单
		/// </summary>
		/// <param name="order_no"></param>
		/// <returns></returns>
		public refund_order_dto Get(string order_no) {
			return context.RefundOrders.Where(c => c.OrderNo == order_no).FromCacheFirstOrDefault<RefundOrder, refund_order_dto>("RefundOrder");
		}

		/// <summary>
		/// 查询退款退货订单
		/// </summary>
		/// <param name="transactionNo"></param>
		/// <returns></returns>
		public refund_order_dto GetByTran(string transactionNo) {
			return context.RefundOrders.Where(c => c.PayInfo.TransactionNo == transactionNo).FromCacheFirstOrDefault<RefundOrder, refund_order_dto>("RefundOrder");
		}

		/// <summary>
		/// 申请退款
		/// </summary>
		/// <param name="dto"></param>
		/// <returns></returns>
		public int ApplyRefund(refund_model dto) {
			//if (context.RefundOrders.Exist(c => c.OrderNo == dto.order_no))
			//	throw new ServerErrorException("退单" + dto.order_no + "已存在", 1001);
			//Order order = null;
			//if (!string.IsNullOrEmpty(dto.orig_order_no) && string.IsNullOrEmpty(dto.transaction_no))
			//	order = context.Orders.FirstOrDefault(c => c.OrderNo == dto.orig_order_no);
			//else
			//	order = context.Orders.FirstOrDefault(c => c.PayInfo.TransactionNo == dto.transaction_no);
			//if (order.Status != OrderStatus.Finish)
			//	throw new ServerErrorException("支付未完成，不可以退款");
			//var t_refund_amt = context.RefundOrders.Where(c => c.OrderId == order.Id && (c.Status == RefundStatus.Walt || c.Status == RefundStatus.Finish))
			//						  .Sum(c => (decimal?)c.Amount) ?? 0;
			//var refund_amt = decimal.Parse(dto.tran_amount) / 100;
			//if (order.Amount - t_refund_amt < refund_amt)
			//	throw new ServerErrorException("退款金额超过原订单金额，不可以退款");

			//RefundOrder model = new RefundOrder();
			//model.OrderNo = dto.order_no;
			//model.ApplyTime = DateTime.Now.ToUnix();
			//model.OrderId = order.Id;
			//model.Amount = refund_amt;
			//model.Status = RefundStatus.Walt;
			//model.PayInfo = new PayInfo {
			//	CreateTime = model.ApplyTime, OrderNo = model.OrderNo, PayNo = model.OrderNo, PayChannel = order.PayInfo.PayChannel,
			//	PayCode = order.PayInfo.PayCode, PayName = order.PayInfo.PayName, PayType = order.PayInfo.PayType, SettleType = order.PayInfo.SettleType
			//};
			////必须赋值，不然接口会出错
			//dto.transaction_no = order.PayInfo.TransactionNo;
			//dto.orig_order_no = order.OrderNo;

			//context.RefundOrders.Add(model);

			//int result = _iUnitOfWork.Commit("RefundOrder");

			//return result;
			return 0;
		}

		/// <summary>
		/// 取消
		/// </summary>
		/// <param name="refund_id"></param>
		/// <returns></returns>
		public int Cancel(long refund_id) {
			RefundOrder model = context.RefundOrders.Find(refund_id);
			if (model.Status != RefundStatus.Walt)
				throw new ServerErrorException("单在商家审核和买家寄回商品时才可以取消");
			model.Status = RefundStatus.Cancel;

			int result = _iUnitOfWork.Commit("RefundOrder");
			return result;
		}

		/// <summary>
		/// 平台提交退款,调用第三方退款API,只有失败的时候才会用到
		/// </summary>
		/// <param name="refund_id"></param>
		/// <returns></returns>
		public string PlatformRefundAmount(long refund_id) {
			RefundOrder model = context.RefundOrders.Find(refund_id);
			var order = model.Order;
			if (model.Status != RefundStatus.Fail)
				throw new ServerErrorException("状态不正确");
			//退款方有没有余额退
			var bill = context.Bills.FirstOrDefault(c => c.MerchantId == order.MerchantId);
			if (bill == null || (bill != null && bill.Balance < model.Amount)) {
				throw new ServerErrorException("退款方余额不足，无法退款");
			}

			var tags = new List<string>();
			tags.Add("RefundOrder");
			string pay_no = model.PayInfo.PayNo;

			model.Status = RefundStatus.Finish;

			int result = _iUnitOfWork.Commit(tags.ToArray());
			if (result > 0) return pay_no;
			return "";
		}

		/// <summary>
		/// 平台退款成功，支付通道原路回退成功后回调方法，如果是用余额支付，一定是成功的，
		/// UI上要可以由财务手动处理退款单为完成，用于第三方的可能的异常
		/// </summary>
		/// <param name="pay_no">提交第三方的交易号</param>
		/// <param name="transaction_no">第三方支付流水号</param>
		/// <param name="pay_time"></param>
		/// <param name="status"></param>
		/// <param name="pay_time">失败原因</param>
		/// <returns></returns>
		public int PlatformRefundAmount(string pay_no, string transaction_no, DateTime? pay_time, RefundStatus status, string fail) {
			RefundOrder model = context.RefundOrders.FirstOrDefault(c => c.PayInfo.PayNo == pay_no);
			if (model.Status != RefundStatus.Walt && model.Status != RefundStatus.Fail)
				throw new ServerErrorException("此退款单账务没有做下发退款");

			var tags = new List<string>();
			List<JPushMessage> messages = new List<JPushMessage>();
			var order = model.Order;
			tags.Add("RefundOrder");

			model.Status = status;
			if (!model.PayInfo.PayTime.HasValue) {
				model.RefundTime = model.PayInfo.PayTime = (pay_time ?? DateTime.Now).ToUnix();
				model.PayInfo.TransactionNo = transaction_no;
			}
			if (status == RefundStatus.Fail) {
				if (string.IsNullOrEmpty(model.Fail))
					model.Fail = fail;
			} else if (status == RefundStatus.Finish) {
				var tgs = _iBillService.RefundAccount(model.OrderNo, transaction_no);
				tags.AddRange(tgs);
			}

			int result = _iUnitOfWork.Commit(tags.ToArray());

			return result;
		}
	}
}
